using System;
using System.Linq;
using QntPlatform.Strategy.CmdCtrl;
using QntPlatform.Strategy.Utility;

namespace QntPlatform.Strategy.S2
{
    /*
    * 行情分析
    * 触发命令
    * 分析命令
    * 买入：行情信息、账户信息
    * 设置止损
    * 设置止盈
    * 监测止损
    * 监测止盈
    * ------------
    * 管道添加--事件处理
    * */
    /// <summary>
    /// 标准信号做单，使用3步止盈,
    /// </summary>
    [ArgInfo(Remark = @"标准信号做单，使用3步止盈，最后一步进行跟踪止盈;
命令格式:{""Period"":60,""islong"":true,""sells"":[1000,1020]}"
)]
    public class BiaoZhun : PeriodTrandBase<BiaoZhun.TradeCmd>
    {
        [ArgInfo(Remark = "可承受止损率,用于仓位计算")]
        decimal stopLossRatio { get; set; } = 0.02m;
         [ArgInfo(Remark = "跟踪止盈回撤率")]
        public decimal StopProfitForSlideRate { get; set; }=0.01m;
      public  static readonly decimal profitSlideDownRate = 0.85m;
        /// <summary>止损计算时atr系数
        /// 
        /// </summary>
        public readonly decimal stopAtrProfit = 0.6m;
        public BiaoZhun()
        {

        }
        protected override bool IsCheckTrend => false;
        void Buy(TradeCmd cmdVal)
        {
            var isLong = cmdVal.IsLong;
            //计算仓位
            var re = Exchange.GetRecordsAsync(cmdVal.Period.Value);
            var tck = Exchange.GetTickerAsync();
            var account = Exchange.GetAccountAsync();
            var kArr = re.Result;
            //var minLow = kArr.Skip(kArr.Length - 7).Min(p => p.Low); // Aggregate((p1, p2) =>(p1 == null || p1.Low > p2.Low)?p2:p1);
            //var atr = (decimal)TA.ATR(kArr, 14).Last();
            decimal stopLoss = StopLossCalc(kArr, isLong.Value);// minLow - atr * 0.5m; //止损价

            var nowPrice = tck.Result.Buy;
            var buyAmount = AmountCalc(account.Result.Balance, stopLoss, nowPrice, isLong.Value);// account.Result.Balance * stopLossRatio / (nowPrice - stopLoss);

            Log.Debug("交易信息计算", new { stopLoss, nowPrice, buyAmount, stopLossRatio });
            //计算止盈止损


            //买卖
            var id = Exchange.CreateOrder(buyAmount, DirectionTo.InFor(isLong)); //  Exchange.BuyAsync(buyAmount);
            //止盈止损添加
            var auto = new TvCmdHandler.AutoSellOrder();
            if (cmdVal.sells.Length != 2)
                throw new QntException("止盈数量错误");
            auto.SourcePrice = nowPrice;

            auto.ProfitPrices = cmdVal.sells.Select(p=> calcProfitSlideDownPrice(nowPrice,p, profitSlideDownRate,isLong.Value)).ToArray();
            auto.SourceOrderId = id.Result;
            auto.SourceAmount = buyAmount;
            auto.Amount = buyAmount;
            auto.Direction = DirectionTo.CloseFor(isLong);
            auto.StopLossPrice = stopLoss;

            // var fun = new MiddleGuoup<Ticker>()
            //      //.AddUse( new StopLoss(auto, this).Execute)
            //      .AddRun(new StepProfit(this, auto).TickerChangeListening)
            //      .Bulid();
            Log.Debug("添加任务信息",auto);
                 new CmdCtrl.StepProfitRun(this, auto, cmdVal.Period.Value) { StopProfitForSlideRate=this.StopProfitForSlideRate}.Init();
            //Exchange.TickerChangeEvent += (p1, p2) => fun.Invoke(p2);
        }
        /// <summary>
        /// 根据止盈滑动率，计算滑动后止盈价
        /// </summary>
        /// <param name="source"></param>
        /// <param name="profitPrice"></param>
        /// <param name="downRate"></param>
        /// <param name="isLong"></param>
        /// <returns></returns>
        public static decimal calcProfitSlideDownPrice(decimal source, decimal profitPrice, decimal downRate, bool isLong)
        {
            return CalcFun.CalcUnitProfit(profitPrice,source,isLong) * downRate * (isLong ? 1 : -1) + source;
        }

        private decimal AmountCalc(decimal balance, decimal stopLoss, decimal nowPrice, bool isLong)
        {
            var longVal = isLong ? 1 : -1;
            var bl = balance;
            if (Exchange is BinanceApi.DApi.USDExchangeImp)
            {
                bl = nowPrice * bl;
            }
            var am = longVal * bl * stopLossRatio / (nowPrice - stopLoss);
            return Exchange.getAmount(am);
        }

        private decimal StopLossCalc(Record[] records, bool isLong)
        {
            var last7 = records.Skip(records.Length - 7); // Aggregate((p1, p2) =>(p1 == null || p1.Low > p2.Low)?p2:p1);
            var top = isLong ? last7.Min(p => p.Low) : last7.Max(p => p.High);
            var atr = (decimal)TA.ATR(records, 14).Last();
            var atrV = isLong ? -atr * stopAtrProfit : atr * stopAtrProfit;
            var stopLoss = top + atrV; //止损价
            Log.Debug("止损计算信息", new { stopLoss, top, atr });
            return stopLoss;
        }


        public override void Execute(TradeCmd info = null)
        {
              Buy(info);
        }

        //protected override void InitStrategyArgs()
        //{
        //    if(Args.TryGetValue("stopLossRatio",out var valStr))
        //    {
        //        stopLossRatio=decimal.Parse(valStr);
        //    }
        //}

        public class TradeCmd:TradeInfo
        {
            //public decimal? Price { get; set; }
            public decimal[] sells { get; set; }
 
        }

    }
}